import datetime  #
import os.path  # 路径管理
import sys  # 获取当前运行脚本的路径 (in argv[0])

# 导入backtrader框架
import backtrader as bt


print("starting ...", bt.__version__)


class TestStrategy(bt.Strategy):
    params = (
        # 持仓够5个单位就卖出
        ("exitbars", 5),
    )

    def log(self, txt, dt=None):
        # 记录策略的执行日志
        dt = dt or self.datas[0].datetime.date(0)
        print("%s, %s" % (dt.isoformat(), txt))

    def __init__(self):
        # 保存收盘价的引用
        self.dataclose = self.datas[0].close

        # 跟踪挂单
        self.order = None

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # broker 提交、接受，买卖订单则什么都不做
            return

        # 检查一个订单是否完成
        # 资金不足时，broker会拒接订单
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    "已买入,价格：%.2f,费用：%.2f,佣金：%.2f"
                    % (order.executed.price, order.executed.value, order.executed.comm)
                )
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            elif order.issell():
                self.log(
                    "已卖出,价格：%.2f,费用：%.2f,佣金：%.2f"
                    % (order.executed.price, order.executed.value, order.executed.comm)
                )
                self.order = None

            # 记录当前交易数量
            self.bar_executed = len(self)
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log("订单取消/保证金不足/拒绝")

        # 其他状态记录为：无挂起订单
        # self.order = None

    def notify_trade(self, trade):
        if not trade.isclosed:
            return

        self.log("交易利润,毛利率 %.2f,净利润%.2f" % (trade.pnl, trade.pnlcomm))

    def next(self):
        # 记录收盘价
        self.log("Close, %.2f" % self.dataclose[0])

        # 如果有订单正在挂起，不操作
        if self.order:
            return

        if not self.position:
            # 今天的收盘价 < 昨天的收盘价
            if self.dataclose[0] < self.dataclose[-1]:
                # 昨天收盘价 < 前天收盘价
                if self.dataclose[-1] < self.dataclose[-2]:
                    # 买入
                    self.log("买入, %.2f" % self.dataclose[0])
                    # 跟踪订单避免重复
                    self.buy()

        else:
            if len(self) >= (self.bar_executed + self.params.exitbars):
                self.log("卖出,%.2f" % self.dataclose[0])
                self.order = self.sell()


# 创建Cerebro引擎
cerebro = bt.Cerebro()

# 为引入策略
cerebro.addstrategy(TestStrategy)

# 加载数据
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
datapath = os.path.join(modpath, "datas\\orcl-1995-2014.txt")

data = bt.feeds.YahooFinanceCSVData(
    dataname=datapath,
    fromdate=datetime.datetime(2000, 1, 1),
    todate=datetime.datetime(2000, 12, 31),
    reversed=False,
)

cerebro.adddata(data)

# Cerebro引擎在后台创建broker(经纪人)，系统默认资金量为10000
# 设置投资金额100000.0
cerebro.broker.setcash(100000.0)

# 设置每笔使用固定交易量
cerebro.addsizer(bt.sizers.FixedSize, stake=10)

# 设置佣金0.001
cerebro.broker.setcommission(commission=0.001)

# 引擎运行前打印期出资金
print("组合期初资金: %.2f" % cerebro.broker.getvalue())
cerebro.run()
# 引擎运行后打期末资金
print("组合期末资金: %.2f" % cerebro.broker.getvalue())

print("ending ok...")
